package robber;

import http.BasicRequest;
import http.util.PrintUtil;
import main.robClass;
import org.apache.commons.lang3.StringUtils;
import timer.saveCoursesManager;
import user.IUser;
import user.impl.robUser.RobUser;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

/**
 * 抽象抢课类
 */

/**
 * 用来分开不同类型抢课的对象类 同时在父类通过模板方法设计模式 实现出了子类变化 父类不变的逻辑
 * 为什么要有抽象模板抢课类？
 * 目的是因为抢课类有一些行为是固定的 我将其行为作为固定的模板
 * 而在根据继承的不同子类再将不同的行为特例化 将不同的职责交给子类去执行
 * 总而言之, 继承AbstractRobber类后的Robber类 都是抢课的业务逻辑
 */

public abstract class AbstractRobber implements IRobber {

    private IUser user;

    /**
     * 搜索课程后的缓存 存放课程课程代码 中文名
     * getIdAndCourseNameCache():{04TJ09=保健推拿}
     */
    private HashMap<String, String> IdAndCourseNameCache = new HashMap<>();
    /**
     * 管理抢课状态
     */
    private boolean isRob;
    /**
     * 发包需要的viewstate
     */
    private HashSet<String> viewState = new HashSet<>();
    /**
     * 发包网络管理类
     */
    private BasicRequest basicRequest;


    public AbstractRobber(IUser user) {
        this.user = user;
        if (this.getIdAndCourseNameCache().isEmpty()) {
            robClass.logger.info("AbstractRobber: 使用缓存课表");
            this.setIdAndCourseNameCache(saveCoursesManager.getGlobalIdAndCourseNameCache());
        }
    }
    /*******************抢课需要的线程***********************/
    /**
     * 线程 - 抢课资源初始化
     */
    class PreRobThread implements Runnable {
        @Override
        public void run() {
            try {
                preRob();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 线程 - 抢课 - 默认
     */
    class RobThread implements Runnable {
        @Override
        public void run() {
            RobUser robUser = (RobUser) getUser();
            if (robUser.getRobClasses().isEmpty()) {
                robClass.logger.info("startRob - " + robUser.getUsername() + " # " + robUser.getStudentName() + "没有要抢课程");
                return;
            }
            start_rob();
        }

    }

    /**
     * 线程 - 抢课 - 疯狂
     */
    class CrazyRobThread implements Runnable {
        @Override
        public void run() {
            RobUser robUser = (RobUser) getUser();
            if (robUser.getRobClasses().isEmpty()) {
                robClass.logger.info("startCrazyRob - " + robUser.getUsername() + " # " + robUser.getStudentName() + "没有要抢课程");
                return;
            }
            robUser.getRobClasses().parallelStream().forEach(course -> rob(course, true));
//            start_crazy_rob();
        }
    }
    /******************************************/

    /**
     * 预初始化资源
     * 登录获取Cookie
     * 搜索课程表 - 加载抢课列表资源
     * 获取firstViewState
     */

    @Override
    public void preRob() throws Exception {
        user.login();
        sleep(50);
        asyncSearchClasses();
        sleep(50);
        pre_rob();
    }

//    @Override
//    public void startCacheRob() throws Exception {
//        start_rob();
//    }

    /**
     * 狂暴模式 此时无声胜有声 直接readTime 10ms 疯狂用缓存发包
     * 狂暴模式目前是普通模式的5、6倍效率
     */
    @Override
    public void startCrazyRob() {
        robClass.logger.info("你已进入狂暴模式!!!! 此时无声胜有声...请安静等待结果!");
        RobUser robUser = (RobUser) this.getUser();

        if (robUser.getRobClasses().isEmpty()) {
            robClass.logger.info("startCrazyRob - " + robUser.getUsername() + " # " + robUser.getStudentName() + "没有要抢课程");
            return;
        }

        try {
            ScheduledExecutorService preRobThread = Executors.newScheduledThreadPool(2);
            preRobThread.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    robClass.logger.info("狂暴模式试探抢课情况线程 - 执行中");
                    try {
                        RobThread robThread = new RobThread();
                        new Thread(robThread).start();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, 0, 2000, TimeUnit.MILLISECONDS);

            ScheduledExecutorService startPeThread = Executors.newScheduledThreadPool(1);
            startPeThread.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    try {
                        try {
                            CrazyRobThread crazyRobThread = new CrazyRobThread();
                            sleep(25);
                            new Thread(crazyRobThread).start();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, 0, 100, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * RobberUtil负责开启
     */
    @Override
    public void startRob() {
        RobUser robUser = (RobUser) this.getUser();
        /**判断是否有要抢的课*/
        if (robUser.getRobClasses().isEmpty()) {
            robClass.logger.info("startRob - " + robUser.getUsername() + " # " + robUser.getStudentName() + "没有要抢课程");
            return;
        }
        //robClass.logger.info("ABS: startRob() : user.getCookies(): " + user.getCookies() + " user: " + user.toString());
//        HashSet<String> cookies = user.getCookies();
        //发现缓存 直接用缓存抢课
//        if (cookies != null && user.getCookies().size() > 0) {
////            robClass.logger.info("发现缓存 直接缓存抢课");
//            asyncSearchClasses();
//            pre_rob();
//        } else {
////            robClass.logger.info("没有缓存 不考虑缓存抢课");
//            preRob();
//        }
        /**开始加载抢课线程池定时任务*/

        try {
            ScheduledExecutorService preRobThread = Executors.newScheduledThreadPool(10);
            preRobThread.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    try {
//                            robClass.logger.info("正在抢课");
                        sleep(10);
                        PreRobThread preRobThread = new PreRobThread();
                        new Thread(preRobThread).start();
                        sleep(10);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, 0, 1000, TimeUnit.MILLISECONDS); /**定时增加抢课资源初始化线程*/
//            ScheduledExecutorService startPeThread = Executors.newScheduledThreadPool(80);
//            startPeThread.scheduleAtFixedRate(new TimerTask() {
//                @Override
//                public void run() {
//                    try {
//                        try {
//                            RobThread robThread = new RobThread();
//                            new Thread(robThread).start();
//                            sleep(45);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            }, 0, 500, TimeUnit.MILLISECONDS); /**定时增加抢课线程*/
            ScheduledExecutorService startPeThread = Executors.newScheduledThreadPool(80);
            startPeThread.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    try {
                        try {
                            RobThread robThread = new RobThread();
                            new Thread(robThread).start();
                            sleep(45);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, 0, 200, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    public void stopRob() {
        stop_rob();
        setRob(false);
    }

    @Override
    public void setTimerRob() {
        setTimer_rob();
    }

    /**
     * template method to implement for subclass
     **/
    /**
     * 正常模式抢课 到时候将疯狂模式归类进来
     */
    protected void start_rob() {
        final RobUser user = (RobUser) this.getUser();
        //具体抢课行为交给子类rob方法处理
        user.getRobClasses().parallelStream().forEach(course -> rob(course, false));
    }

    ;

    protected abstract void stop_rob();

    protected abstract void setTimer_rob();

    /**
     * 具体抢课行为由子类rob方法决定
     * 课程Id 疯狂模式
     */
    protected abstract void rob(String classId, boolean isCrazyMode);

    /**
     * PE(体育课):分派robCourseNums(3)个线程进行must3Params资源初始化
     * Common(公选课):分派robCourseNums(3)个线程进行must3Params资源初始化
     */
    protected void pre_rob() {
        ((RobUser) user).getRobClasses().parallelStream().forEach(courseId ->
                initPreRob(courseId)
        );
    }

    ;

    protected abstract void initPreRob(String courseId);

    protected abstract HashMap<String, String> sync_search_Classes();

    protected abstract void async_search_Classes();

//    protected abstract void start_crazy_rob();

    /**
     * network
     **/
    public BasicRequest getBasicRequest() {
        if (basicRequest == null) {
            basicRequest = new BasicRequest();
        }
        return basicRequest;
    }


    /**
     * 同步搜索课程 用来人工录入选课信息时候用
     */
    @Override
    public HashMap<String, String> syncSearchClasses() throws Exception {
        PrintUtil.printTitle("同步搜索课程");
        return sync_search_Classes();
    }

    /**
     * 异步搜索课程 用来寻找抢课信息时候用
     */
    @Override
    public void asyncSearchClasses() {
        async_search_Classes();
    }

    /**
     * 资源预初始化
     */
    @Override
    public void preInitResources() {
        try {
            RobUser robUser = (RobUser) this.getUser();
            if (robUser.getRobClasses().isEmpty()) {
                robClass.logger.info("preInitResources - " + robUser.getUsername() + " # " + robUser.getStudentName() + "没有要抢课程");
                return;
            }
            preRob();
        } catch (Exception e) {
            PrintUtil.printError(user, Thread.currentThread());
        }

    }


    /**
     * getter/setter
     **/

    public IUser getUser() {
        return user;
    }

    public void setUser(IUser user) {
        this.user = user;
    }


    public String getRandomFirstViewState() {
        Random random = new Random();
        if (this.viewState.size() <= 0) return null;
        //robClass.logger.info("random.nextInt(this.viewState.size():" + this.viewState.size());
        return (String) viewState.toArray()[random.nextInt(this.viewState.size())];
    }


    public HashSet<String> getFirstViewState() {
        return viewState;
    }

    public void setFirstViewState(HashSet<String> viewState) {
        this.viewState = viewState;
    }


    public boolean isRob() {
        return isRob;
    }

    public void setRob(boolean rob) {
        isRob = rob;
    }


    public void putIdAndCourseNameCache(String courseName, String courseId) {
        if (StringUtils.isBlank(courseName) || StringUtils.isBlank(courseName)) {
            return;
        }
        this.IdAndCourseNameCache.put(courseName, courseId);
        saveCoursesManager.getGlobalIdAndCourseNameCache().put(courseName, courseId);
    }

    public HashMap<String, String> getIdAndCourseNameCache() {
//        if(IdAndCourseNameCache.isEmpty()){
//            robClass.logger.info("用户没有课表,目前从缓存中获取课表");
//            return saveCoursesManager.getGlobalIdAndCourseNameCache();
//        }
        return IdAndCourseNameCache;
    }

    public HashMap<String, String> setIdAndCourseNameCache(HashMap<String, String> IdAndCourseNameCache) {
        this.IdAndCourseNameCache = IdAndCourseNameCache;
        return this.IdAndCourseNameCache;
    }

    public HashSet<String> getViewState() {
        return viewState;
    }
}
